/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#include "glheaders.h"

#include "graphView.h"

#include <assert.h>
#include <string.h>
#include <math.h>
#include "renderUtils.h"
#include "mouseUtils.h"
#include "graph.h"
#include "layout.h"
#include "timing.h"
#include "controller.h"

#include <algorithm>

/****** GraphView ***************/


GraphView::GraphView(const char *title): SimpleGraphView(title) {
	setPropertyFloat("Node.Shadow", 0.0);
	setPropertyFloat("Node.Border", 1.0);
	setPropertyStringList("Edge.Size", "Default", "edge");
	setPropertyStringList("Node.Size", "Default", "node");

	setPropertyStringList("Node.Label", "Default", "node");
	setPropertyFloat("Label.Opacity Factor", 1.0);
	setPropertyFloat("Label.Border Factor", 0.0);
	setPropertyFloat("Label.Box Opacity", 0.0);
	setPropertyFloat("Edge.Border", 1.0);

	labels = 0;
	nodeSizes = 0;
	edgeSizes = 0;
	validNodeSizes = false;
	validEdgeSizes = false;
	
	circleList = shadowList = circleLineList = 0;
}

GraphView::~GraphView() {
}

void GraphView::allocateNodeGeometry(int n) {
	if(n!=numVertices) {
		if(nodeSizes) delete nodeSizes;
		nodeSizes = new float[n];
		if(labels) delete labels;
		labels = new string[n];
	}
	SimpleGraphView::allocateNodeGeometry(n);
}

void GraphView::allocateEdgeGeometry(int n) {
	if(n!=numIndices) {
		if(edgeSizes) delete edgeSizes;
		edgeSizes = new float[n];
	}
	SimpleGraphView::allocateEdgeGeometry(n);
}

void GraphView::initGraphics() {
	// Set up call lists
	if(circleList==0) {
		circleList = glGenLists(1);
		glNewList(circleList, GL_COMPILE);
		circle(1.0);
		glEndList();
		circleLineList = glGenLists(1);
		glNewList(circleLineList, GL_COMPILE);
		circle(1.0, true);
		glEndList();
	}
	if(shadowList == 0) {
		shadowList = glGenLists(1);
		glNewList(shadowList, GL_COMPILE);
		glBegin(GL_QUADS);
		glTexCoord2d(0,0); glVertex2f(-1.15,-1.5);
		glTexCoord2d(0,1); glVertex2f(-1.15, 1.15);
		glTexCoord2d(1,1); glVertex2f( 1.5, 1.15);
		glTexCoord2d(1,0); glVertex2f( 1.5,-1.5);
		glEnd();
		glEndList();
	}
	if(objectID==0) {
		int w, h;
		w = 64; h = 64;
		int m = 0;
		
		unsigned char *data = new unsigned char[w*h];
		for(int i=0;i<w;i++) {
			for(int j=0;j<h;j++) {
				float x = (float) i/(float) w - 0.5;
				float y = (float) j/(float) h - 0.5;
				float r = 5.0*(0.24 - (x*x + y*y));
				if(r<0) r = 0.0;
				if(r>1) r = 1.0;
				data[m] = (unsigned char) ((r)*255);
				m++;
			}
		}
		
		
		glGenTextures(1, &objectID);
		glBindTexture(GL_TEXTURE_2D, objectID);
		glEnable(GL_TEXTURE_2D);
		
		glTexImage2D(GL_TEXTURE_2D,
								 0,
								 GL_ALPHA32F_ARB,
								 w,
								 h,
								 0,
								 GL_ALPHA,
								 GL_UNSIGNED_BYTE,
								 data);
		
		GLenum err = glGetError();
		if(err!=GL_NO_ERROR) {
			char *s =  (char* ) gluErrorString(err);
			print("Got an error setting up the Texture [%d = %s]\n", err, s);
			fflush(stdout);
		}
		
		
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
		delete data;
		glDisable(GL_TEXTURE_2D);
		
	}

}

void GraphView::updateNodeLabels() {
	assert(labels);
	int m = 0;
	NodeIterator *it = graph->createNodeIterator();
	for(it->begin();it->hasMoreElements();) {
		Node * node = (Node*) it->next(); 
		int i = node->getIndex();
		labels[m] = graph->getAsString(node, PROPERTY(getPropertyString("Node.Label")));
		m++;
	}
	graph->destroyIterator(it);
	validNodeLabels = true;
}

void GraphView::updateNodeSizes() {
	assert(nodeSizes);
	string thresholdFlag = getName() + ".Flag.AboveThresh";
	int m = 0;
	NodeIterator *it = graph->createNodeIterator();
	for(it->begin();it->hasMoreElements();) {
		Node * node = (Node*) it->next(); 
		int i = node->getIndex();
//		bool aboveThresh = node->getPropertyBool(thresholdFlag);
//		if(aboveThresh) { // To be done
		if(true) {
			float size = graph->getAsFloat(node, PROPERTY(getPropertyString("Node.Size")));
			nodeSizes[m] = size;
			m++;
		}        
	}
	graph->destroyIterator(it);
	validNodeSizes = true;
}

void GraphView::updateEdgeSizes() {
	string thresholdFlag = getName() + ".Flag.AboveThresh";
	int m = 0;
	EdgeIterator *it = graph->createEdgeIterator();
	for(it->begin();it->hasMoreElements();) {
		Edge * edge = (Edge*) it->next(); 
		int j = edge->getNode1()->getIndex();
		bool aboveThresh = edge->getPropertyBool(thresholdFlag);
		if(aboveThresh) {
			float size = graph->getAsFloat(edge, PROPERTY(getPropertyString("Edge.Size")));
			edgeSizes[m] = size;
			m++;
		}        
	}
	graph->destroyIterator(it);
	validEdgeSizes = true;
}

void GraphView::render() {
	// Pretty much the same as SimpleGraphView
	// Maybe add "predrawCustome() postdrawCustom()" to avoid repeating code?
	assert(graph);
	timestamp t1 = now();
	int N = (int) graph->numNodes();
	allocateNodeGeometry(N);
	
	initGraphics();
	
	string layoutName = getPropertyString("Graph.Layout");
	layout = controller->getLayout(layoutName);
	
	glPushMatrix();
	
	if(layoutChanged || !validGeometry) {
		createNodeGeometry();
		validNodeSizes = false;
		validNodeLabels = false;
	}
	if(!validIndices) {
		createEdgeGeometry();
		validEdgeSizes = false;
	}
	if(!validColors) {
		updateNodeColors();
		updateEdgeColors();
	}
	if(!validEdgeSizes) {
		updateEdgeSizes();
	}
	if(!validNodeSizes) {
		updateNodeSizes();
	}
	if(!validNodeLabels) {
		updateNodeLabels();
	}
	
	drawEdgeGeometry();
	drawNodeGeometry();
	
	drawNodeLabels();
	
	glPopMatrix();
	timestamp t2 = now();
	layoutChanged = false;
	validGeometry = true;
	validColors = true;
	validIndices = true;
}

void GraphView::drawNodeGeometry() {
	if(!vertices) return;
	if(!nodeSizes) return;
	if(!colors) return;
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	float shadowSize = getPropertyBool("Node.Shadow");
	float border = getPropertyFloat("Node.Border");
	float nodeSize = getPropertyFloat("Node.Size Factor")*1.0/1000.0;//*xpixels(1.0);
	float fColor = 0.0;
	glDisable(GL_TEXTURE_2D);
	for(int i=0;i<numVertices;i++) {
		float x = vertices[2*i+0];
		float y = vertices[2*i+1];
		glPushMatrix();
		glTranslatef(x,y,0);
		float size = nodeSizes[i];
		glScalef(size*nodeSize, size*nodeSize, size*nodeSize);
		if(shadowSize>0) {
			glEnable(GL_TEXTURE_2D);
			glBindTexture(GL_TEXTURE_2D, objectID);
			//glColor4f(0,0,0, colors[4*i+3]);
			glColor4f(fColor,fColor,fColor, colors[4*i+3]);
			glCallList(shadowList);
			glDisable(GL_TEXTURE_2D);
		}
		glColor4fv(&(colors[4*i]));
		glCallList(circleList); 
		if(border>0) {
			glLineWidth(border);
			glColor4f(fColor,fColor,fColor, colors[4*i+3]);
			glCallList(circleLineList); 
		}
		glPopMatrix();
	}
	glLineWidth(1);
}

void GraphView::drawNodeLabels() {
	if(!colors) return;
	if(!labels) return;
	float boxOpacityFactor = getPropertyFloat("Label.Box Opacity");
	float labelOpacityFactor = getPropertyFloat("Label.Opacity Factor");
	//float labelShadowFactor = getPropertyFloat("Label.Shadow Factor");
	float labelBorderFactor = getPropertyFloat("Label.Border Factor");
	for(int i=0;i<numVertices;i++) {
		float x = vertices[2*i+0];
		float y = vertices[2*i+1];
		glPushMatrix();
		glTranslatef(x,y,0);
		string label = labels[i];
		if(label!="") {
			float textw, texth;
			float tx, ty, th, tw;
			getTextBox(tx, ty, textw, texth, (char*) label.c_str(), "center", "middle");
			float boxOpacity = colors[4*i+3]*boxOpacityFactor;
			float labelOpacity = colors[4*i+3]*labelOpacityFactor;
			float labelBorderOpacity = colors[4*i+3]*labelBorderFactor;
			float dx = xpixels(2.5);
			float dy = ypixels(2.5);
			float dx0 = xpixels(-2.5);
			float dy0 = ypixels(-2.5);
			glColor4f(0.95,0.95,0.95,boxOpacity);
			roundRectangle(tx + 0.5*dx0, ty + 0.5*dy0, fmax(0, textw + dx), fmax(0,texth + dy), dx, dy);

			glColor4f(0,0,0,labelBorderOpacity);
			roundRectangleLine(tx + 0.5*dx0, ty + 0.5*dy0, fmax(0, textw + dx), fmax(0,texth + dy), dx, dy);
			//shadowRectangle(tx + dx0, ty + dy0, textw + 2*dx, texth + 2*dy, 2*dx, 2*dy, labelShadowOpacity);

			glColor4f(0,0,0,labelOpacity);
			renderText(0, 0, label.c_str(), "center", "middle");
		}
		glPopMatrix();
	}
}


void GraphView::drawEdgeGeometry() {
	if(!indices) return;
	if(!edgeSizes) return;
	float opacity = getPropertyFloat("Edge.Opacity Factor");
	float factor = getPropertyFloat("Edge.Size Factor");
	float border = getPropertyFloat("Edge.Border");

	float fColor = 0.0;
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glEnableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);

	for(int m = 0; m < numIndices; m++) {
		float thickness = edgeSizes[m];
		glLineWidth(thickness*factor+border);
		glColor4f(fColor,fColor,fColor,edgeColors[4*m+3]); 
		glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, &(indices[2*m]));

		glLineWidth(thickness*factor);
		glColor4fv(&(edgeColors[4*m]));
		glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, &(indices[2*m]));
	}
	glLineWidth(1);
	glEnd();
	glDisableClientState(GL_VERTEX_ARRAY);

}

void GraphView::update(string property) {
	SimpleGraphView::update(property);
	if(property=="Edge.Size") {
		validEdgeSizes = false;
	}
	if(property=="Node.Size") {
		validNodeSizes = false;
	}
	if(property=="Node.Labels") {
		validNodeLabels = false;
	}
}

/*

void GraphView::getNodeLocation(int i, float &x, float &y) {
    if(layout) {
        layout->getLocation(i, x, y);
    } else if((int) vnodes.size()>i) {
        x = vnodes[i].x;
        y = vnodes[i].y;
    }
}

void GraphView::setNodeLocation(int i, float x, float y) {
    if(layout) {
        layout->setLocation(i, x, y);
        layout->updated();
    }
    if((int) vnodes.size()>i) {
        vnodes[i].x = x;
        vnodes[i].y = y;
    }
    layoutUpdated();
}

void GraphView::setGraph(Graph *g) {
    View::setGraph(g);
    createVisualNodes();
}

void GraphView::createVisualNodes() {
    vnodes.clear();
    for(unsigned int i=0;i<graph->numNodes();i++) {
        float x = 2*M_PI*(float) i/(float) graph->numNodes();
        NodeInfo n;
        n.x = 0.3*cos(x);
        n.y = 0.3*sin(x);
        n.vx = 0;
        n.vy = 0;
        vnodes.push_back(n);
    }

}


bool GraphView::pickNode(float x, float y) {
	float nodeScale = getPropertyFloat("Node size");

	ElementIterator *it = graph->createNodeIterator();
	for(it->begin();it->hasMoreElements();) {
		Node *node = (Node*) it->next();
		int i = node->getIndex();
        if(node->isVisible()) {
            float px,py;
            getNodeLocation(i,px,py);
            float d2 = (px-x)*(px-x)+(py-y)*(py-y);
            float r = nodeScale*(graph->getAsFloat(node,"Node radiusLine"),1.0);
            if(d2<r*r) {
								curpick =	i;	
                selectElement(node, selectionMarker);
                return true;
            }
        }
	}
	graph->destroyIterator(it);
	return false;
}

void GraphView::click(float x, float y, int modifiers) {
    View::click(x, y, modifiers);

    float rx, ry;
    toView(x,y,rx,ry);

    if(!pickNode(rx,ry)) {
			if(curpick>=0) {
				PropertyBag * node = graph->getNode(curpick);
				if(node) selectElement(node, 0);
			}
			curpick = -1;
    }
}
void GraphView::release(float px, float py, int modifiers) {
    View::release(px,py,modifiers);
}
void GraphView::drag(float px, float py, float dx, float dy, int modifiers) {
    float rdx, rdy;
    toViewDisplacement(dx,dy,rdx,rdy);
    if(curpick>=0) {
        float rx, ry;
        toView(px,py,rx,ry);
        setNodeLocation(curpick, rx, ry);
    } else {
        View::drag(px, py, dx, dy, modifiers);
        if(performingSelection) {
            controller->colorUpdated();
        }
    }
}

void GraphView::drawNodeId(Node *node, int i) {
    float nodeTransparency = getPropertyFloat("Node transparency");
    float transparency = nodeTransparency*(graph->getAsFloat(node, PROPERTY(getPropertyString("Node opacity")),1.0));
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    {
			float x, y;
			getNodeLocation(i,x,y);
			glTranslatef(x,y,0);
			string label = graph->getAsString(node,PROPERTY(getPropertyString("Label"))); 
			if(label!="") {
					renderRoundTextBox(0, 0, label.c_str(), "center", "middle", xpixels(5.0), ypixels(5.0), transparency);
			}
    }
    glPopMatrix();
}

void GraphView::initGraphics() {
    if(!indices) updateIndices();
    if(circleList==0) {
        circleList = glGenLists(1);
        glNewList(circleList, GL_COMPILE);
        circle(1.0);
        glEndList();
        circleLineList = glGenLists(1);
        glNewList(circleLineList, GL_COMPILE);
        circle(1.0, true);
        glEndList();
    }
    if(shadowList == 0) {
        shadowList = glGenLists(1);
        glNewList(shadowList, GL_COMPILE);
        glBegin(GL_QUADS);
        glTexCoord2d(0,0); glVertex2f(-1.15,-1.5);
        glTexCoord2d(0,1); glVertex2f(-1.15, 1.15);
        glTexCoord2d(1,1); glVertex2f( 1.5, 1.15);
        glTexCoord2d(1,0); glVertex2f( 1.5,-1.5);
        glEnd();
        glEndList();
    }
    if(objectID==0) {
        int w, h;
        w = 64; h = 64;
        int m = 0;

        unsigned char *data = new unsigned char[w*h];
        for(int i=0;i<w;i++) {
            for(int j=0;j<h;j++) {
                float x = (float) i/(float) w - 0.5;
                float y = (float) j/(float) h - 0.5;
                float r = 5.0*(0.24 - (x*x + y*y));
                if(r<0) r = 0.0;
                if(r>1) r = 1.0;
                data[m] = (unsigned char) ((r)*255);
                m++;
            }
        }


        glGenTextures(1, &objectID);
        printf("Created Texture [%d]\n", objectID); fflush(stdout);
        glBindTexture(GL_TEXTURE_2D, objectID);
        glEnable(GL_TEXTURE_2D);

        glTexImage2D(GL_TEXTURE_2D,
                     0,
                     GL_ALPHA32F_ARB,
                     w,
                     h,
                     0,
                     GL_ALPHA,
                     GL_UNSIGNED_BYTE,
                     data);

        GLenum err = glGetError();
        if(err!=GL_NO_ERROR) {
            char *s =  (char* ) gluErrorString(err);
            print("Got an error setting up the Texture [%d = %s]\n", err, s);
            fflush(stdout);
        }


        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
        printf("Deleting data\n");
        delete data;
        printf("Deleting data DONE\n");
        glDisable(GL_TEXTURE_2D);
	
    }

}

void GraphView::drawNodes() {
	string nodeFilterProperty = PROPERTY(getPropertyString("Node filter"));
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    bool shadow = getPropertyBool("Node shadow");
    glDisable(GL_TEXTURE_2D);
    float nodeSize = getPropertyFloat("Node size");
	ElementIterator *it = graph->createNodeIterator();
	for(it->begin();it->hasMoreElements();) {
		Node *node = (Node*) it->next();
		int i = node->getIndex();
			bool filterPass = graph->getAsBoolean(node,nodeFilterProperty);
			node->setVisible(filterPass);
        if(node->isVisible()) {
            float x, y;
            getNodeLocation(i,x,y);
            //glVertex2f(x,y);
            glPushMatrix();
            glTranslatef(x,y,0);

            glScalef(nodeSize, nodeSize, nodeSize);
            if(this->getPropertyString("Node radiusFill")!="Default"){
                float fValue_ori = graph->getAsFloat(node,  PROPERTY(getPropertyString("Node radiusFill")), 1.0,  true );
                glScalef(fValue_ori, fValue_ori, fValue_ori);
            }
            if(shadow) {
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, objectID);
                //glColor4f(0,0,0, colors[4*i+3]);
                glColor4f(fColor_front,fColor_front,fColor_front, colors[4*i+3]);
                glCallList(shadowList);
                glDisable(GL_TEXTURE_2D);
            }
            glColor4fv(&(colors[4*i]));
            glCallList(circleList); //radius fill

            if(this->getPropertyString("Node radiusFill")!=this->getPropertyString("Node radiusLine")){
                glScalef(nodeSize, nodeSize, nodeSize); // reset size
                if(this->getPropertyString("Node radiusLine")!="Default"){
                    float fLineDefault = this->getPropertyFloat("Node radiusFill_ratio"); //a ratio to adjust RadiusLine
                    float fValue_ori = graph->getAsFloat(node,  PROPERTY(getPropertyString("Node radiusLine")), 1.0,  true );
                    glScalef(fLineDefault*fValue_ori, fLineDefault*fValue_ori, fLineDefault*fValue_ori);
                }
            }
            glColor4f(fColor_front,fColor_front,fColor_front, colors[4*i+3]);
            glCallList(circleLineList); //radiusline


            glPopMatrix();
        }
    }
	graph->destroyIterator(it);
}

void GraphView::colorUpdated() {
    invalidateColors = true;
}
void GraphView::layoutUpdated() {
    layoutChanged = true;
}

void GraphView::render() {
    timestamp t1 = now();
    int N = (int) graph->numNodes();
    createArrays(N);

    assert(graph);
    assert(graph->getStatManager());

    initGraphics();

    string layoutName = getPropertyString("Layout");
    layout = controller->getLayout(layoutName);

    glPushMatrix();

    if(layoutChanged || invalidateGeometry) {
        updateVertices();
    }
    if(invalidateGeometry) {
        updateIndices();
    }
    if(invalidateColors) {
        updateColors();
        updateEdgeColors();
    }


    if(!this->getPropertyBool("Hide edges")){
        renderLines();
    }


    if( !this->getPropertyBool("Hide nodes") ){
        drawNodes();


    }

    if( !this->getPropertyBool("Hide labels")){
			NodeIterator *it = graph->createNodeIterator();
			for(it->begin();it->hasMoreElements();) {
				Node *node = (Node*) it->next();
							if(node->isVisible()) {
									drawNodeId(node,node->getIndex());
							}
					}
			graph->destroyIterator(it);
    }

    glPopMatrix();
    timestamp t2 = now();
    glDisable(GL_POINT_SPRITE);
    layoutChanged = false;
    invalidateGeometry = false;
    invalidateColors = false;
}

void GraphView::save(FILE *) {
}

void GraphView::load(vector<string> ) {
}

void GraphView::update(string property) {

    //#ifdef USING_NODESIZEDEBUGGER
    if(property=="NodeSize"){
        float fSize = this->getPropertyFloat("NodeSize",0.05);

        print("update NODE SIZE :%f\n",fSize);

        boolSizePrinted = false;
    }
    //#endif

    invalidateGeometry = true;
    invalidateColors = true;

}

void GraphView::tic() {
	ElementIterator *it = graph->createNodeIterator();
	for(it->begin();it->hasMoreElements();) {
		Node *node = (Node*) it->next();
        node->setVisible(true);
    }
	graph->destroyIterator(it);
    //  myLayout->updateVisible();
    //  myLayout->update();
}
 */

View *createGraphView(string name) {
    GraphView* mainView = new GraphView(name.c_str());
    mainView->setLocation(0.0,0.0);
    mainView->setSize(1.0,1.0);
    mainView->setVisible(true);
    mainView->addCloseButton();
    mainView->addTransparentButton();
    mainView->addSelectionWidget();
    return mainView;
}


